/**
  ETFAna project, Anyang Normal University && IMP-CAS
  \class ETFTimer4
  \brief a plastic scintillator (square) plate with its four corners each coupled
  with a PMT
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2022-04-25
  \date 2021-04-25 last modified
  \attention
  changelog
  <table>
  <tr>  <th>Date         <th>Author      <th>Description                   </tr>
  <tr>  <td>2022-04-25   <td>Asia Sun    <td>file created                  </tr>
  </table>

  \copyright Copyright (c) 2021-2024 Anyang Normal U. && IMP-CAS with LGPLv3 LICENSE
*/
#include <cstring>
#include <TClonesArray.h>
#include <TGraph.h>
#include "ETFTimer4.h"
#include "ETFDetectorManager.h"
#include "ETFRawChannel.h"
#include "ETFPlaHit.h"
#include "ETFMath.h"
#include "ETFMsg.h"
#include "ETFParaManager.h"
#include "ETFYaml.h"

ETFTimer4::ETFTimer4(const char *name, double length) : ETFTimer(name, length){
  const int chId0 = fChIdConfig.as<int>();
  // assign channel ids for the 4*2 channels //
  // [8]: strip Id; [9-11]: [uv-uh-dv-dh-uq-dq]
  const bool isq = fQChIdConfig.good();
  for(int i = 0; i < 2; i++){ // loop over 2 strips
    if(ETFMath::endwith(name, "_v")){ // vme channels
      const int chid0 = chId0 + i*2;
      SetChMap(chid0, fDetId + (i<<8)); // UV
      SetChMap(chid0 + 1, fDetId + (i<<8) + (2<<9)); // DV
    } // end if(vme)
    else{ // PXI channels
      const int chid0 = chId0 + i*4;
      SetChMap(chid0, fDetId + (i<<8)); // UV
      SetChMap(chid0 + 1, fDetId + (i<<8) + (1<<9)); // UH
      SetChMap(chid0 + 2, fDetId + (i<<8) + (2<<9)); // DV
      SetChMap(chid0 + 3, fDetId + (i<<8) + (3<<9)); // DH
    } // end if
    if(isq){
      SetChMap(fQChIdConfig[2*i].as<int>(), fDetId + (i<<8) + (4<<9)); // UQ
      SetChMap(fQChIdConfig[2*i + 1].as<int>(), fDetId + (i<<8) + (5<<9)); // DQ
    } // end if(Q)
  } // end for over i
} // end ctor

// add the data channel to the detector
void ETFTimer4::Assign(const ETFRawChannel *ch, unsigned uid){
  const int udvh = uid>>9 & 0x7;
  if(1 == udvh || 3 == udvh) return; // ommit (SFE16) TOT channel
  AddHit(ch, uid>>8 & 0xF);
} // end member function Assign

void ETFTimer4::AddHit(const ETFRawChannel *ch, int idvh){
  ETFPlaHit *hit = nullptr;
  const int stripId = idvh & 0x1; // catagorize them artificially in 2 strips
  for(auto p : *fHits){
    ETFPlaHit *h = static_cast<ETFPlaHit *>(p);
    if(stripId == h->GetStripId()){ // old strip
      hit = h; continue;
    } // end if
  } // end for
  if(!hit && ch->IsT()){ // create a new strip: Q ch does not trigger this
    hit = static_cast<ETFPlaHit *>(fHits->ConstructedAt(fHits->GetEntriesFast()));
    hit->Initialize();
    hit->SetStripId(stripId);
    hit->SetLength(fLength);
    static double pos[3]{};
    hit->SetPosition(pos);
    hit->SetDelay(fDelay);
    hit->SetName(ETFMsg::Form("%s%d", GetName(), stripId));
    TransformToLabRef(hit);
    fIsFired = true;
  } // end if(hit is nullptr)
  if(ch->IsT()) hit->SetTChannel(ch, idvh>>1);
  else hit->SetQChannel(ch, idvh>>1);
} // end member function AddHit

double ETFTimer4::GetTime() const{
  const int nh = fHits->GetEntriesFast();
  if(!nh) ETFMsg::Error("ETFStart", "GetTime: No hits in Tstop4");
  if(1 == nh) ETFMsg::Error("ETFStart", "GetTime: only 1 strip hits found in Tstop4");
  const double t0 = dynamic_cast<ETFPlaHit *>(fHits->At(0))->GetTime();
  const double t1 = dynamic_cast<ETFPlaHit *>(fHits->At(1))->GetTime();
  return (t0+t1)/2.;
} // end member function GetTime

// 
int ETFTimer4::GetFiredStatus() const{
  const int nh = fHits->GetEntriesFast();
  if(!nh) return -2;
  if(1 == nh) return -1;
  const int s0 = dynamic_cast<ETFPlaHit *>(fHits->At(0))->GetFiredStatus();
  const int s1 = dynamic_cast<ETFPlaHit *>(fHits->At(1))->GetFiredStatus();
  const int sta = s0+s1;
  if(8 == sta) return 4;
  if(4 == sta) return 5;
  return sta;
} // end member function GetFiredStatus

// add strip to fGDumb
void ETFTimer4::ConstructGraph(){
  if(fGDumb->GetN()) return; // has called

  fGDumb->SetMarkerStyle(28);
  fGDumb->SetMarkerColor(30); // gray
  double p[3]{};
  TransformToLabRef(p);
  fGDumb->SetPoint(0, p[2], p[0]);
} // end member function ConstructGraph

void ETFTimer4::DrawHits(){
  for(const auto &p : *fHits) if(p){
    ETFPlaHit *h = dynamic_cast<ETFPlaHit *>(p);
    h->GetGHit()->SetMarkerStyle(21);
    if(h->GetFiredStatus() == 4) h->Draw();
  } // end for and if
} // end member function DrawHits
